# -*- coding: utf-8 -*-
import os
import logging
import numpy as np 
import pandas as pd
import matplotlib.pyplot as plt
import json
from cvxopt import solvers, matrix

dirs = 'logs'
if not os.path.exists(dirs):
    os.makedirs(dirs)
logging.basicConfig(filename='%s/factor_cvxopt.log' % dirs, level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
# 逻辑应该是一只产品对应多个股票代码,最后用多个股票的价格去预测此产品的走向
    
# 测试功能,用于生成随机的json代码 
def creat_json():
    # 产品代码的dict
    my_product_dict = {}
    # 股票代码
    my_stock_dict = {}
    stock_inner__dict = {}
    inner_dict = {}
    code = {
        "000300": [3886.9189, 3862.4796, 3854.8625, 3852.9292, 3927.1729, 3938.3434, 3898.6354, 3871.1443, 3808.863, 3748.6412, 3766.282, 3811.843, 3760.8543, 3766.3257, 3843.4886, 3828.7015, 3755.4941, 3756.8765, 3763.6461, 3793.0001, 3774.5981, 3834.1877, 3878.6767, 3871.6152, 3893.0565, 3872.8383, 3909.2933, 3924.0975, 3892.8442, 3864.0507, 3903.0637, 3921.2421, 3906.2081, 3854.5825, 3827.217, 3816.498, 3833.2599, 3804.0093, 3723.3724, 3802.3759]
      }
    
    # 生成日期列表
    date_list = []
    [date_list.append(i) for i in range(20180101, 20180131)]
    
    #生成产品的dict
    for i in range(4310,4320):
        inner_dict = {}
        data = list(np.random.uniform(1,2,30))
        for j in range(30):
            inner_dict[date_list[j]] = data[j]
        my_product_dict[i] = inner_dict
    
    # 生成股票的dict 
    for i in range(30):
        stock_inner__dict[date_list[i]] = code["000300"][i]/300
        
    my_stock_dict = {
            "000300":stock_inner__dict
            }
    my_product_json = json.dumps(my_product_dict)
    my_stock_json = json.dumps(my_stock_dict)
    return my_product_json, my_stock_json


def creat_json2():
    with open('接口入参产品.txt', mode='r', encoding='utf-8') as f_product:
        my_product_json = f_product.read()
        my_product_dict = json.loads(my_product_json)
        
        
    with open('接口入参基准.txt', 'r', encoding='utf-8') as f_stock:
        my_stock_json = f_stock.read()
        my_stock_dict = json.loads(my_stock_json)
        x_df = pd.DataFrame.from_dict(my_stock_dict, orient='columns')
        
        y_df = pd.DataFrame.from_dict(my_product_dict, orient='columns')
    #    for column in y_df.columns:
    #        sss = y_df[column].dropna()
    #        qqq = pd.merge(sss, x_df, how='inner')
        
        for i in range(y_df.shape[1]-4):
            y_df_train = y_df.iloc[:, i:i+1].dropna()
            train = pd.concat([y_df_train, x_df], axis=1, join='inner') 
        return train
    
def factor_cvxopt():   
    """
    :param :
    :return: W权重系数, r_square拟合度, w_sum权重之和, result_test预测值, r_new另一种方法的拟合度
    """
# =============================================================================
#     # 此处用于测试时,自己创建参数
#     # my_product_json, my_stock_json = creat_json()    
#     x_dict = json.loads(my_stock_json)
#     y_dict = json.loads(my_product_json)
#     # 每行是日期,每列是每个股票的代码
#     x_df = pd.DataFrame.from_dict(x_dict, orient='columns')
#     y_df = pd.DataFrame.from_dict(y_dict, orient='columns')
# =============================================================================
    train = creat_json2()
    y_df = train.iloc[:, 0:1]
    x_df = train.iloc[:, 1:]
    x_df = x_df/x_df.iloc[0]
    
    x_row, x_col = x_df.shape
    y_mean = y_df.mean(axis=0)    
    row_one = pd.DataFrame(np.ones([x_row, 1]))
    row_one.index=x_df.index
    # 这个用于P,q的参数,与G,h无关
    p_x_df = pd.concat([row_one, x_df], axis=1)
    
    #x_matrix = np.matrix(x_df)
    p_x_matrix = np.matrix(p_x_df)
    y_matrix = np.matrix(y_df)   
    
    P = matrix(np.dot(2 * p_x_matrix.T, p_x_matrix))
    q = matrix(np.dot(-2 * p_x_matrix.T, y_matrix))
    
    g_zero = np.zeros([x_col*2, x_col])
    col_zero = np.zeros([x_col*2, 1])
    for i in range(x_col):
        g_zero[i][i] = 1
        g_zero[x_col+i][i] = -1   
    g_zero = np.concatenate([col_zero, g_zero],axis=1)
    
    h = np.zeros([x_col*2])
    h[:x_col] = 1
    G = matrix(g_zero)
    h = matrix(h)  
    a_para = np.ones([1, x_col+1])
    a_para[0][0] = 0 
    A = matrix(a_para)
    b_para = np.ones([1,1])
    b = matrix(b_para)
    sol = solvers.qp(P, q, G, h, A, b)  
    W = np.array([sol['x'][0], sol['x'][1], sol['x'][2], sol['x'][3], sol['x'][4], sol['x'][5], 
                  sol['x'][6], ])
    
    w_sum = sum(W) - W[0]
    
    result_test = np.dot(p_x_matrix, W)
    # 预测值和实际值的误差
    C = result_test - y_matrix.T
    # 残差平方和
    MSE = np.dot(C, C.T)
    # 取[]中的第0个元素
    SSE = MSE[0]
    
    SST = 0
    y_mean = np.tile(y_mean, (y_matrix.shape[0],1))
    SST = (np.array(y_matrix - y_mean)**2).sum()


    # 拟合度公式为 r**2  = (总方差-残差)/总方差 = 1 - (残差/总方差)
    r_square = 1 - float(SSE / SST)
    y_2 = np.dot(y_matrix, y_matrix.T).sum()
    r_new = 1 - float(SSE / y_2)**0.5
    return W, r_square, w_sum, result_test, r_new
    
    
    

    
    
if __name__ == '__main__':
    W, r_square, w_sum, result_test, r_new = factor_cvxopt()
    
    train = creat_json2()
    y_df = train.iloc[:, 0:1]
    x_df = train.iloc[:, 1:]/1000
    result_test = pd.DataFrame(result_test.T, index=y_df.index)
    y_index = pd.to_datetime(y_df.index)
    plt.plot(y_index, result_test)
    plt.plot(y_index, y_df)
    plt.show()
    plt.close()
    
    
# =============================================================================
#     result_test = result_test.T
#     my_product_json, my_stock_json = creat_json()    
#     x_dict = json.loads(my_product_json)
#     y_dict = json.loads(my_stock_json)
#     # 每行是日期,每列是每个产品的代码
#     x_df = pd.DataFrame.from_dict(x_dict, orient='columns')
#     y_df = pd.DataFrame.from_dict(y_dict, orient='columns')
#     result_test = pd.DataFrame(result_test, index=y_df.index)
#     plt.plot(result_test.index, result_test)
#     plt.plot(y_df.index, y_df)
#     plt.show()
#     plt.close()
# =============================================================================






